package com.yc.spring.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAspect {

    // 切面 = 增强 + 切点(表达式)
    // 前置增强
    // Spring 通过接口注入当前执行的业务方法
    @Before("execution(* com.yc.spring.vote.dao.*.select*(..))")
    public void before(JoinPoint jp){
        // 日志输出
        System.out.println("************* 前置增强开始 **************");
        System.out.println("jp = " + jp);
        System.out.println("方法签名 jp.getSignature() = " + jp.getSignature());
        System.out.println("方法参数 jp.getArgs() = " + jp.getArgs());
        System.out.println("目标对象 jp.getTarget() = " + jp.getTarget());
        System.out.println("************* 前置增强结束 **************");
    }

    @Pointcut("execution(* com.yc.spring.vote.dao.*.select*(..))")
    public void myPointcut(){}

    @After("myPointcut()")
    public void after(JoinPoint jp){
        // 日志输出
        System.out.println("************* 后置增强开始 **************");
        System.out.println("jp = " + jp);
        System.out.println("方法签名 jp.getSignature() = " + jp.getSignature());
        System.out.println("方法参数 jp.getArgs() = " + jp.getArgs());
        System.out.println("目标对象 jp.getTarget() = " + jp.getTarget());
        System.out.println("************* 后置增强结束 **************");
    }

    @Pointcut("execution(* com..dao.*.*(..))")
    public void myPointcut1(){}

    @AfterReturning(value = "myPointcut1()", returning = "res")
    public void afterReturning(JoinPoint jp, Object res){
        System.out.println("************* 返回增强开始 **************");
        System.out.println("jp.getSignature() = " + jp.getSignature());
        System.out.println("返回结果: " + res);
        System.out.println("************* 返回增强结束 **************");
    }

    @Pointcut("execution(* com..biz.*.register(..))")
    public void myPointcat2(){}

    @AfterThrowing(value = "myPointcat2()", throwing = "t")
    public void afterThrowing(JoinPoint jp, Throwable t){
        System.out.println("************* 异常增强开始 **************");
        System.out.println("jp = " + jp);
        System.out.println("异常t = " + t);
        System.out.println("************* 异常增强结束 **************");
    }


    @Pointcut("execution(* com.yc.spring.vote.web.VoteAction.test*())")
    public void myPointcut2(){}

    @Before("myPointcut2()")
    public void before1(JoinPoint jp){
        System.out.println(jp.getSignature()+"----------before1----------");
    }
    @After("myPointcut2()")
    public void after1(JoinPoint jp){
        System.out.println(jp.getSignature()+"----------after1----------");
    }
    @AfterReturning("myPointcut2()")
    public void afterReturning1(JoinPoint jp){
        System.out.println(jp.getSignature()+"----------afterReturning1----------");
    }@AfterThrowing("myPointcut2()")
    public void afterThrowing1(JoinPoint jp){
        System.out.println(jp.getSignature()+"----------afterThrowing1----------");
    }

    /**
     * try{
     *              before 前置增强
     *     业务方法
     *              afterReturning  返回增强
     * } cath ( 异常 e){
     *              afterThrowing   异常增强
     * } finally{
     *              after  后置增强
     * }
     *
     */

    // 环绕增强: 性能监控
    @Around("execution(* com..biz.*.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {

        // 1. 环绕增强的连接点对象, 必须手动执行业务方法
        // 2. 环绕增强的方法返回, 表示返回业务方法的返回值
        long begin, end;
        try {
            System.out.println("pjp = " + pjp);
            begin = System.currentTimeMillis();
            // 手动执行业务方法
            Object res = pjp.proceed();
            end = System.currentTimeMillis();
            long time = end - begin;
            System.out.println(pjp.getSignature() + "运行了" + time + "毫秒");
            // 返回业务方法的返回值
            return res;
        } catch (Throwable throwable) {
            throw throwable;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        B b = new B();
        A e = new C();
        C c = (C) e;
        C f = (C) a;  //语法没有问题, 执行有问题
    }


}

interface  A {

}

class B implements A{

}

class C implements A{

}
